﻿using APP.BaseClass;
using APP.IO;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace APP.OpenCV
{
    /// <summary>
    /// 像素比较 https://www.cnblogs.com/farewell-farewell/p/5887068.html
    /// </summary>
    public class OpenCVOCRHelper
    {

        public struct FindContourModel
        {
            public double x, y;                    //轮廓位置
            public int order;                      //轮廓向量contours中的第几个

            //public bool operator <(con m)
            //{
            //    if (y > m.y) return false;
            //    else if (y == m.y)
            //    {
            //        if (x < m.x) return true;
            //        else return false;
            //    }
            //    else return true;
            //}

        }
        FindContourModel[] conModel = new FindContourModel[15];


        public struct OCRResultModel
        {
            public double bi;
            public int num;

            public bool IsRecognize { get; set; }
            //public bool operator <(result m)
            //{
            //    if (bi < m.bi) return true;
            //    else return false;
            //}

            //public bool operator >(result m)
            //{
            //    if (bi < m.bi) return true;
            //    else return false;
            //}

        }

        public class OCRSetting
        {
            public int Number { get; set; }
            public int Thresh_Min { get; set; }
            public int Thresh_Max { get; set; }
        }

        List<OCRSetting> ocrSettingList = new List<OCRSetting>()
        {
            new OCRSetting{ Number=1, Thresh_Min=130, Thresh_Max=220 },
            new OCRSetting{ Number=2, Thresh_Min=130, Thresh_Max=220 },
            new OCRSetting{ Number=1, Thresh_Min=130, Thresh_Max=220 },
            new OCRSetting{ Number=1, Thresh_Min=130, Thresh_Max=220 },
            new OCRSetting{ Number=1, Thresh_Min=130, Thresh_Max=220 },

        };

        OCRResultModel[] resultModel = new OCRResultModel[15];

        Mat[] num = new Mat[15];
        Mat sample;

        static int thresh_Min = 115;
        static int thresh_Max = 255;
        public FeedBack<int> OCRText(string picturePath)
        {
            FeedBack<int> result = new FeedBack<int>();

            Mat srcImage = Cv2.ImRead(picturePath);
            Mat grayImage = new Mat();
            Mat Image = new Mat();
            Mat dstImage = new Mat();
            srcImage.CopyTo(dstImage);
            Cv2.CvtColor(srcImage, grayImage, ColorConversionCodes.BGR2GRAY);
            Cv2.Threshold(grayImage, Image, thresh_Min, thresh_Max, ThresholdTypes.BinaryInv);

            //定义轮廓和层次结构
            //Vector<Vector<Point>> contours;
            //Vector<Vec4i> hierarchy;

            Cv2.FindContours(Image, out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxNone);
            if (contours.Length > 0)
            {
                //Mat resultImage = new Mat(Image.Size(), MatType.CV_8UC3);
                //Cv2.DrawContours(resultImage, contours, -1, new Scalar(255, 0, 0), 2);
                //var folder = PathHelper.GetPath(FolderType.Temp, "ImageContour");
                //var fileName = Path.GetFileName(picturePath);
                //var savePath = Path.Combine(folder, fileName);
                //Cv2.ImWrite(savePath, resultImage);
                //Cv2.ImShow("123", resultImage);
                //Cv2.WaitKey();

                for (int itemIndex = 0; itemIndex < contours.Length; itemIndex++)
                {
                    var item = contours[itemIndex];
                    var itemRect = Cv2.BoundingRect(item);
                    Mat resultImage = new Mat(Image, itemRect);
                    //var newMap = resultImage;

                    var folder = PathHelper.GetPath(FolderType.Temp, "ImageContour");
                    var fileName = Path.GetFileNameWithoutExtension(picturePath);
                    var fileExtension = Path.GetExtension(picturePath);
                    var savePath = Path.Combine(folder, fileName + itemIndex + fileExtension);
                    Cv2.DrawContours(resultImage, contours, itemIndex, new Scalar(255, 0, 0), 2);
                    Cv2.ImWrite(savePath, resultImage);
                }

            }
            else
            {
                return result;
            }


            int i = 0;
            Point2f[,] pp = new Point2f[5, 4];
            //Vector<Vector<Point>>::iterator It;
            Rect[] rect = new Rect[30];
            if (contours.Length > 10)
            {

            }
            foreach (var It in contours)
            {
                //画出可包围数字的最小矩形
                Point2f[] vertex = new Point2f[4];
                rect[i] = Cv2.BoundingRect(It);
                vertex[0] = rect[i].TopLeft;//矩阵左上角的点
                vertex[1].X = (float)rect[i].TopLeft.X;
                vertex[1].Y = (float)rect[i].BottomRight.Y; //矩阵左下方的点
                vertex[2] = rect[i].BottomRight;//矩阵右下角的点
                vertex[3].X = (float)rect[i].BottomRight.X;
                vertex[3].Y = (float)rect[i].TopLeft.Y;//矩阵右上方的点

                for (int j = 0; j < 4; j++)
                {
                    Cv2.Line(dstImage, vertex[j].ToPoint(), vertex[(j + 1) % 4].ToPoint(), new Scalar(0, 0, 255), 1);
                }

                conModel[i].x = (vertex[0].X + vertex[1].X + vertex[2].X + vertex[3].X) / 4.0;//根据中心点判断图像的位置
                conModel[i].y = (vertex[0].Y + vertex[1].Y + vertex[2].Y + vertex[3].Y) / 4.0;
                conModel[i].order = i;
                i++;
            }

            //sort(conModel, conModel + i);

            for (int j = 0; j < i; j++)
            {
                int k = conModel[j].order;
                var rectItem = rect[k];
                if (srcImage[rectItem] == null)
                {

                }
                num[j] = new Mat();
                srcImage[rectItem].CopyTo(num[j]);
                Cv2.CvtColor(num[j], num[j], ColorConversionCodes.BGR2GRAY);
                Cv2.Threshold(num[j], num[j], thresh_Min, thresh_Max, ThresholdTypes.BinaryInv);
                if (num[j] == null)
                {

                }
                deal(num[j], j + 1);
            }


            var list = resultModel.Where(x => x.IsRecognize).ToList();

            if (list.Count > 0)
            {
                result.Success = true;
                result.Data = list.First().num;
            }
            return result;
        }

        void Threshold(Mat src, Mat sample, int m)
        {
            try
            {
                Cv2.CvtColor(sample, sample, ColorConversionCodes.BGR2GRAY);
                Cv2.Threshold(sample, sample, thresh_Min, thresh_Max, ThresholdTypes.BinaryInv);
                resultModel[m].bi = compare(src, sample);
                resultModel[m].num = m;
                if (resultModel[m].bi > 0.6)
                {
                    resultModel[m].IsRecognize = true;
                }
            }
            catch (Exception ex)
            {
            }
        }

        void deal(Mat src, int order)
        {
            var folder = @"C:\repo\Play\MinesweeperAutoScanDemo\APP.OpenCV\Resources\";

            sample = Cv2.ImRead(folder + "0.jpg");
            Threshold(src, sample, 0);

            sample = Cv2.ImRead(folder + "1.jpg");
            Threshold(src, sample, 1);

            sample = Cv2.ImRead(folder + "2.jpg");
            Threshold(src, sample, 2);

            sample = Cv2.ImRead(folder + "3.jpg");
            Threshold(src, sample, 3);

            sample = Cv2.ImRead(folder + "4.jpg");
            Threshold(src, sample, 4);

            sample = Cv2.ImRead(folder + "5.jpg");
            Threshold(src, sample, 5);

            sample = Cv2.ImRead(folder + "6.jpg");
            Threshold(src, sample, 6);

            sample = Cv2.ImRead(folder + "7.jpg");
            Threshold(src, sample, 7);

            sample = Cv2.ImRead(folder + "8.jpg");
            Threshold(src, sample, 8);

            sample = Cv2.ImRead(folder + "9.jpg");
            Threshold(src, sample, 9);
            //Cv2.Sort(resultModel, resultModel + 10);
            //sort(resultModel, resultModel + 10);

            if (resultModel[9].bi > 0.6)
            {
                resultModel[9].IsRecognize = true;
                Console.WriteLine($"第{order}个数字为{resultModel[9].num}");
                Console.WriteLine($"识别精度为{resultModel[9].bi}");
            }
            else
            {
                Console.WriteLine($"第{order}个数字无法识别");
            }
        }

        double compare(Mat src, Mat sample)
        {
            double same = 0.0, difPoint = 0.0;
            Mat now = new Mat();
            Cv2.Resize(sample, now, src.Size());
            int row = now.Rows;
            int col = now.Cols * now.Channels();
            for (int i = 0; i < 1; i++)
            {
                var data1 = src.At<Vec3b>(i);
                var data2 = now.At<Vec3b>(i);
                for (int j = 0; j < row * col; j++)
                {
                    int a = data1[j];
                    int b = data2[j];
                    if (a == b) same++;
                    else difPoint++;
                }
            }
            return same / (same + difPoint);
        }

    }
}
